package com.zzzzzz.common.util;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import org.springframework.web.multipart.commons.CommonsMultipartFile;

import com.mongodb.gridfs.GridFSDBFile;
import com.zzzzzz.common.id.UUIDGenerator;
import com.zzzzzz.core.data.filestore.FileData;
import com.zzzzzz.core.data.filestore.SimpleFileData;

public class FileUtils {
	
	public static SimpleFileData getFileData(CommonsMultipartFile files) throws IOException {
		String fileName = files.getFileItem().getName();
		InputStream inputStream = files.getInputStream();
		String contentType = files.getContentType();
		String extension = getImageExtension(fileName);
		fileName = UUIDGenerator.get() + StringPool.PERIOD + extension;
		return new SimpleFileData(fileName, inputStream, contentType);
	}
	
	public static FileData getResizedImageData(CommonsMultipartFile files, int maxWidth, int maxHeight, boolean fixedDimension) throws IOException {
		String fileName = files.getFileItem().getName();
		InputStream inputStream = files.getInputStream();
		String contentType = files.getContentType();
		String extension = getImageExtension(fileName);
		fileName = UUIDGenerator.get() + StringPool.PERIOD + extension;
		Map<String, Object> map = resizeImage(inputStream, extension, maxWidth, maxHeight, fixedDimension);
		InputStream scaledInputStream = (InputStream) map.get("scaledInputStream");
		int width = (Integer) map.get("width");
		int height = (Integer) map.get("height");
		return new FileData(fileName, scaledInputStream, contentType, width, height);
	}
	
	public static FileData getCroppedImageData(GridFSDBFile originalGridFSDBFile, int x, int y, int rectWidth, int rectHeight) throws IOException {
		String fileName = originalGridFSDBFile.getFilename();
		InputStream inputStream = originalGridFSDBFile.getInputStream();
		String contentType = originalGridFSDBFile.getContentType();
		String extension = getImageExtension(fileName);
		fileName = UUIDGenerator.get() + StringPool.PERIOD + extension;
		InputStream scaledInputStream = cropImage(inputStream, extension, x, y, rectWidth, rectHeight);
		return new FileData(fileName, scaledInputStream, contentType, rectWidth, rectHeight);
	}
	
	public static Map<String, Object> resizeImage(InputStream sourceInputStream, String extension, int maxWidth, int maxHeight, boolean fixedDimension) throws IOException {
		Map<String, Object> map = new HashMap<String, Object>();
		BufferedImage sourceBufferedImage = ImageIO.read(sourceInputStream);
		int type = sourceBufferedImage.getType() == 0 ? BufferedImage.TYPE_INT_RGB : sourceBufferedImage.getType();
		
		float calculatedWidth = 0;
		float calculatedHeight = 0;
		if(fixedDimension) {
			calculatedWidth = maxWidth;
			calculatedHeight = maxHeight;
		}else {
			float aspectRatio = (float) sourceBufferedImage.getWidth() / (float) sourceBufferedImage.getHeight();

			if (aspectRatio > 1) {
				calculatedWidth = maxWidth;
				calculatedHeight = maxWidth / aspectRatio;

				if (calculatedHeight > maxHeight) {
					calculatedWidth = maxHeight * aspectRatio;
					calculatedHeight = calculatedWidth / aspectRatio;
				}
			} else {
				calculatedWidth = maxHeight * aspectRatio;
				calculatedHeight = maxHeight;

				if (calculatedWidth > maxWidth) {
					calculatedHeight = maxWidth / aspectRatio;
					calculatedWidth = calculatedHeight * aspectRatio;
				}
			}
		}
		BufferedImage resizedBufferedImage = getResizedBufferedImage(sourceBufferedImage, type, (int)calculatedWidth, (int)calculatedHeight);
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		ImageIO.write(resizedBufferedImage, extension, os);
		InputStream scaledInputStream = new ByteArrayInputStream(os.toByteArray());
		map.put("width", (int)calculatedWidth);
		map.put("height", (int)calculatedHeight);
		map.put("scaledInputStream", scaledInputStream);
		return map;
	}
	
	public static InputStream cropImage(InputStream sourceInputStream, String extension, int x, int y, int rectWidth, int rectHeight) throws IOException {
		BufferedImage sourceBufferedImage = ImageIO.read(sourceInputStream);
		int type = sourceBufferedImage.getType() == 0 ? BufferedImage.TYPE_INT_RGB : sourceBufferedImage.getType();

		BufferedImage resizedBufferedImage = getCroppeddBufferedImage(sourceBufferedImage, type, x, y, rectWidth, rectHeight);
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		ImageIO.write(resizedBufferedImage, extension, os);
		InputStream scaledInputStream = new ByteArrayInputStream(os.toByteArray());
		return scaledInputStream;
	}

	private static BufferedImage getResizedBufferedImage(BufferedImage sourceBufferedImage, int type, int width, int height) {
		// Create empty image with new dimensions
		BufferedImage resizedBufferedImage = new BufferedImage(width, height, type);
		Graphics2D graphics = (Graphics2D) resizedBufferedImage.getGraphics();

		// Draw to scaled image
		graphics.drawImage(sourceBufferedImage, 0, 0, width, height, null);
		graphics.dispose();
		return resizedBufferedImage;
	}
	
	private static BufferedImage getCroppeddBufferedImage(BufferedImage sourceBufferedImage, int type, int x, int y, int rectWidth, int rectHeight) {
		// Create empty image with new dimensions
		BufferedImage resizedBufferedImage = new BufferedImage(rectWidth, rectHeight, type);
		Graphics2D graphics = (Graphics2D) resizedBufferedImage.getGraphics();

		// Draw to crop image
		graphics.drawImage(sourceBufferedImage, 0, 0, rectWidth, rectHeight, x, y, x + rectWidth, y + rectHeight, null);
		graphics.dispose();
		return resizedBufferedImage;
	}

	public static String getImageExtension(String fileName) {
		int index = fileName.lastIndexOf(StringPool.PERIOD);
		String extension = StringPool.BLANK;
		if(index > 0) {
			extension = fileName.substring(index+1);
			extension = extension.toLowerCase();
		}
		return extension;
	}
	
}
